using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using T.FAS.Runtime.Base.Common;

namespace T.FAS.Runtime.Expression.Plugin.DingDing
{
    public static class DingDingUtil
    {
        private static readonly String DING_DING_API_URL = "https://oapi.dingtalk.com/robot/send?access_token=";
        /// <summary>
        /// 发送Text类型消息
        /// </summary>
        /// <param name = "content">消息内容</param>
        /// <param name = "mobiles">要@的人的手机号列表</param>
        /// <param name = "accessToken">钉钉机器人AccessToken</param>
        public static void SendTextMsg(string content, List<string> mobiles, string accessToken)
        {
            var jsonContent = ConstructTextMsg(content, mobiles);
            SendMsg(jsonContent, mobiles, accessToken);
        }

        /// <summary>
        /// 发送MarkDown格式消息
        /// </summary>
        /// <param name = "title">消息标题</param>
        /// <param name = "content">消息内容</param>
        /// <param name = "mobiles">要@的人的手机号列表</param>
        /// <param name = "accessToken">钉钉机器人AccessToken</param>
        public static void SendMarkDownMsg(string title, string content, List<string> mobiles, string accessToken, string secret = "", bool isAtAll = false)
        {
            var jsonContent = ConstructMarkDownMsg(title, content, mobiles, isAtAll);
            SendMsg(jsonContent, mobiles, accessToken, secret);
        }

        /// <summary>
        /// 发送FeedCard格式消息
        /// </summary>
        /// <param name = "links"></param>
        /// <param name = "accessToken">钉钉机器人AccessToken</param>
        public static void SendFeedCardMsg(List<DingDingFeedCardLink> links, string accessToken)
        {
            var jsonContent = ConstructFeedCardMsg(links);
            SendMsg(jsonContent, null, accessToken);
        }

        /////////////////////////////////////////////////内部类及私有方法//////////////////////////////////////
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name = "content"></param>
        /// <param name = "mobiles"></param>
        /// <param name = "accessToken"></param>
        private static void SendMsg(string content, List<string> mobiles, string accessToken, string secret = "")
        {
            string url = DING_DING_API_URL + accessToken;
            if (!string.IsNullOrEmpty(secret))
            {
                var sign = CalcSign(secret, out var timestamp);
                url += $"&timestamp={timestamp}&sign={sign}";
            }

            DingDingMsgResult result = null;
            string resultMsg = null;
            HttpWebResponse response = GetDingDingResponse(url, content);
            using (Stream mystream = response.GetResponseStream())
            {
                try
                {
                    var reader = new StreamReader(mystream);
                    resultMsg = reader.ReadToEnd();
                    result = JsonConvert.DeserializeObject<DingDingMsgResult>(resultMsg);
                }
                catch (Exception e)
                {
                    LogUtil.Log($"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_2119745765", "反序列化钉钉消息失败,发送信息为：{0},返回信息为：{1},异常信息为：{2}", content, resultMsg, e)}", "Expression");
                }
            }

            if (result == null)
            {
                LogUtil.Log($"{T.ServiceComponent.I18N.Service.TermService.Current.GetText("T_FAS_fasr_Expression_38492292", "钉钉消息发送失败,返回数据为null")}", "Expression");
            }
            else if (result.errcode != "0")
            {
                LogUtil.Log($"{T.ServiceComponent.I18N.Service.TermService.Current.GetTextFormatted("T_FAS_fasr_Expression_1039371452", "钉钉消息发送异常,异常编号：{0},异常信息：{1},发送目标Url:{2},待发送的消息体：{3}", result.errcode, resultMsg, url, content)}", "Expression");
            }
        }
        /// <summary>
        /// 构造Text类型消息
        /// </summary>
        /// <param name = "content"></param>
        /// <param name = "mobiles"></param>
        /// <returns></returns>
        private static string ConstructTextMsg(string content, List<string> mobiles)
        {
            var textMsg = new DingDingTextMsg()
            { //消息类型
            msgtype = "text", //消息内容
 text = new DingDingTextContent()
            {content = content}, //At人列表
 at = new DingDingAt()
            {isAtAll = false, atMobiles = mobiles}};
            return JsonConvert.SerializeObject(textMsg);
        }

        /// <summary>
        /// 构造MarkDown类型消息
        /// </summary>
        /// <param name = "title"></param>
        /// <param name = "content"></param>
        /// <param name = "mobiles"></param>
        /// <returns></returns>
        private static string ConstructMarkDownMsg(string title, string content, List<string> mobiles, bool isAtAll = false)
        {
            var markDownMsg = new DingDingMarkDownMsg()
            { //消息类型
            msgtype = "markdown", //消息内容
 markdown = new DingDingMarkDownContent()
            {title = title, text = content}, //At人列表
 at = new DingDingAt()
            {isAtAll = isAtAll, atMobiles = mobiles}};
            return JsonConvert.SerializeObject(markDownMsg);
        }

        /// <summary>
        /// 构造FeedCard类型消息
        /// </summary>
        /// <param name = "links"></param>
        /// <returns></returns>
        private static string ConstructFeedCardMsg(List<DingDingFeedCardLink> links)
        {
            var feedCardMsg = new DingDingFeedCardMsg()
            { //消息类型
            msgtype = "feedCard", //消息内容  
 feedCard = new DingDingFeedCardContent()
            {links = links, }, };
            return JsonConvert.SerializeObject(feedCardMsg);
        }

        /// <summary>
        /// 获得钉钉消息响应
        /// </summary>
        /// <param name = "requestURL"></param>
        /// <param name = "content"></param>
        /// <returns></returns>
        private static HttpWebResponse GetDingDingResponse(string requestURL, string content)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestURL);
            request.Method = "POST";
            request.ContentType = "application/json;charset=UTF-8";
            request.Timeout = 30000;
            // Encode the data
            byte[] encodedBytes = Encoding.UTF8.GetBytes(content);
            request.ContentLength = encodedBytes.Length;
            // Write encoded data into request stream
            Stream requestStream = request.GetRequestStream();
            requestStream.Write(encodedBytes, 0, encodedBytes.Length);
            requestStream.Close();
            return (HttpWebResponse)request.GetResponse();
        }

        private static string CalcSign(string secret, out long timestamp)
        {
            timestamp = GetTimeStamp();
            string stringToSign = timestamp + "\n" + secret;
            var encoding = new System.Text.ASCIIEncoding();
            byte[] keyByte = encoding.GetBytes(secret);
            byte[] messageBytes = encoding.GetBytes(stringToSign);
            using (var hmacsha256 = new HMACSHA256(keyByte))
            {
                byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                return HttpUtility.UrlEncode(Convert.ToBase64String(hashmessage), Encoding.UTF8);
            }
        }

        private static long GetTimeStamp()
        {
            long currenttimemillis = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            return currenttimemillis;
        }
    }
}